package com.geek.project.geekauthgateway.component;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.geek.project.geekauthstarter.service.JwtService;
import com.geek.project.geekcommon.response.ResultResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;
import java.util.Map;


@Component
public class AuthGatewayFilterFactory extends AbstractGatewayFilterFactory<AuthGatewayFilterFactory.PathConfig> {

    @Autowired
    private JwtService jwtService;

    public AuthGatewayFilterFactory() {
        super(AuthGatewayFilterFactory.PathConfig.class);
    }

    @Override
    public GatewayFilter apply(PathConfig config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                ServerHttpRequest request = exchange.getRequest();
                ServerHttpResponse response = exchange.getResponse();
                String path = request.getURI().getPath();
                Boolean flag = false;
                for (String authPath : config.getAuthPaths()) {
                    // 如果白名单中有一个包含当前路径
                    if (path.indexOf(authPath) != -1){
                        flag = true;
                        break;
                    }
                }
                // 不在拦截名单中，放行
                if (!flag){
                    return chain.filter(exchange);
                }
                String token = "";
                // 异步请求，通过头信息获取token
                List<String> tokenList = request.getHeaders().get("authorization");
                if(!CollectionUtils.isEmpty(tokenList)) {
                    token = tokenList.get(0);
                }
                // 判断token是否为空
                if (StrUtil.isEmpty(token)) {
                    return toLogin(response);
                }
                try {
                    // 解析jwt，获取登录信息
                    Map<String, Object> map = jwtService.getInfoFromToken(token);

                    // 判断token是否被盗用
                    String ip = map.get("ip").toString();
                    // 当前请求的ip
//                    String curIp = IpUtils.getIpAddress(request);
//                    if (!StringUtils.pathEquals(ip, curIp)){
//                        return toLogin(response);
//                    }

                    // 传递登录信息给后续服务
                    String userId = map.get("userId").toString();
                    // 将userId转变成request对象。mutate：转变的意思
                    request.mutate().header("userId", userId).build();
                    exchange.mutate().request(request).build();

                    // 放行
                    return chain.filter(exchange);
                } catch (Exception e) {
                    return toLogin(response);
                }
            }
        };
    }

    private Mono<Void> toLogin(ServerHttpResponse response){
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        ResultResponse resultResponse = new ResultResponse().put("code", "401").put("msg", "请登录后操作");
        DataBuffer buffer = response.bufferFactory().wrap(JSONUtil.toJsonStr(resultResponse).getBytes());
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        return response.writeWith(Mono.just(buffer));

//        response.setStatusCode(HttpStatus.SEE_OTHER);
//        response.getHeaders().set(HttpHeaders.LOCATION, "http://127.0.0.1/login");
//        return response.setComplete();
    }

    @Override
    public ShortcutType shortcutType() {
        return ShortcutType.GATHER_LIST;
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("authPaths");
    }


    public static class PathConfig{
        private List<String> authPaths;

        public List<String> getAuthPaths() {
            return authPaths;
        }

        public void setAuthPaths(List<String> authPaths) {
            this.authPaths = authPaths;
        }
    }
}
